use core::ptr::copy_nonoverlapping;

use super::Encode;

impl Encode for &[u8] {
    const ENCODE_MIN_LEN: usize = 1;
    fn to_bytes(&self, buf: &mut [u8]) -> Option<usize> {
        let len = self.len();
        if buf.len() < (1 + len) {
            return None;
        }
        unsafe {
            buf[0] = len as u8;
            copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr().add(1), len);
        }
        Some(len + 1)
    }
    unsafe fn to_bytes_unsafe(&self, buf: &mut [u8]) -> usize {
        let len = self.len();
        buf[0] = len as u8;
        copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr().add(1), len);
        len + 1
    }
}

impl Encode for u8 {
    const ENCODE_MIN_LEN: usize = 1;
    fn to_bytes(&self, buf: &mut [u8]) -> Option<usize> {
        if buf.len() < Self::ENCODE_MIN_LEN {
            return None;
        }
        buf[0] = *self;
        Some(1)
    }
    unsafe fn to_bytes_unsafe(&self, buf: &mut [u8]) -> usize {
        buf[0] = *self;
        1
    }
}

impl Encode for u16 {
    const ENCODE_MIN_LEN: usize = 2;
    fn to_bytes(&self, buf: &mut [u8]) -> Option<usize> {
        if buf.len() < Self::ENCODE_MIN_LEN {
            return None;
        }
        buf[0] = (*self >> 8) as u8;
        buf[1] = (*self) as u8;
        Some(2)
    }
    unsafe fn to_bytes_unsafe(&self, buf: &mut [u8]) -> usize {
        buf[0] = (*self >> 8) as u8;
        buf[1] = (*self) as u8;
        2
    }
}

impl Encode for u32 {
    const ENCODE_MIN_LEN: usize = 4;
    fn to_bytes(&self, buf: &mut [u8]) -> Option<usize> {
        if buf.len() < Self::ENCODE_MIN_LEN {
            return None;
        }
        buf[0] = (*self >> 24) as u8;
        buf[1] = (*self >> 16) as u8;
        buf[2] = (*self >> 8) as u8;
        buf[3] = *self as u8;
        Some(4)
    }
    unsafe fn to_bytes_unsafe(&self, buf: &mut [u8]) -> usize {
        buf[0] = (*self >> 24) as u8;
        buf[1] = (*self >> 16) as u8;
        buf[2] = (*self >> 8) as u8;
        buf[3] = *self as u8;
        4
    }
}

impl Encode for i8 {
    const ENCODE_MIN_LEN: usize = 1;
    fn to_bytes(&self, buf: &mut [u8]) -> Option<usize> {
        (*self as u8).to_bytes(buf)
    }
    unsafe fn to_bytes_unsafe(&self, buf: &mut [u8]) -> usize {
        (*self as u8).to_bytes_unsafe(buf)
    }
}

impl Encode for i16 {
    const ENCODE_MIN_LEN: usize = 2;
    fn to_bytes(&self, buf: &mut [u8]) -> Option<usize> {
        (*self as u16).to_bytes(buf)
    }
    unsafe fn to_bytes_unsafe(&self, buf: &mut [u8]) -> usize {
        (*self as u16).to_bytes_unsafe(buf)
    }
}

impl Encode for i32 {
    const ENCODE_MIN_LEN: usize = 4;
    fn to_bytes(&self, buf: &mut [u8]) -> Option<usize> {
        (*self as u32).to_bytes(buf)
    }
    unsafe fn to_bytes_unsafe(&self, buf: &mut [u8]) -> usize {
        (*self as u32).to_bytes_unsafe(buf)
    }
}

impl Encode for () {
    const ENCODE_MIN_LEN: usize = 0;
    fn to_bytes(&self, _buf: &mut [u8]) -> Option<usize> {
        Some(0)
    }
    unsafe fn to_bytes_unsafe(&self, _buf: &mut [u8]) -> usize {
        0
    }
}
